/**
 * 编码解码工具库
 *
 * 支持的编码格式：
 * 1. Hex（十六进制）
 * 2. Base16
 * 3. Base32
 * 4. Base45
 * 5. Base58
 * 6. Base62（支持自定义编码表）
 * 7. Base64
 * 8. Base64URL（URL 安全变种）
 * 9. Base85
 * 10. Base91
 * 11. Base100（Emoji 编码）
 * 12. SafeURL（URL 转义编码）
 * 13. Morse（摩斯电码，支持自定义分隔符）
 */
export const encodeUtil = {
  /**
   * 将字符串转换为Uint8Array
   * @param str 输入字符串
   * @returns Uint8Array
   */
  stringToUint8Array(str: string): Uint8Array {
    const encoder = new TextEncoder();
    return encoder.encode(str);
  },

  /**
   * 将Uint8Array转换为字符串
   * @param uint8Array 输入Uint8Array
   * @returns 字符串
   */
  uint8ArrayToString(uint8Array: Uint8Array): string {
    const decoder = new TextDecoder();
    return decoder.decode(uint8Array);
  },

  /**
   * Hex编码（十六进制）
   * @param str 要编码的字符串
   * @returns 十六进制编码结果
   */
  toHex(str: string): string {
    if (!str) return '';
    const uint8Array = this.stringToUint8Array(str);
    return Array.from(uint8Array)
      .map(byte => byte.toString(16).padStart(2, '0'))
      .join('');
  },

  /**
   * Hex解码（十六进制）
   * @param hex 要解码的十六进制字符串
   * @returns 解码后的原始字符串
   */
  fromHex(hex: string): string {
    if (!hex) return '';
    const bytes = new Uint8Array(hex.length / 2);
    for (let i = 0; i < hex.length; i += 2) {
      bytes[i / 2] = parseInt(hex.substr(i, 2), 16);
    }
    return this.uint8ArrayToString(bytes);
  },

  /**
   * Base16编码
   * @param str 要编码的字符串
   * @returns Base16编码结果
   */
  toBase16(str: string): string {
    return this.toHex(str);
  },

  /**
   * Base16解码
   * @param hex 要解码的Base16字符串
   * @returns 解码后的原始字符串
   */
  fromBase16(hex: string): string {
    return this.fromHex(hex);
  },

  /**
   * Base32编码
   * @param str 要编码的字符串
   * @returns Base32编码结果
   */
  toBase32(str: string): string {
    if (!str) return '';
    const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    const uint8Array = this.stringToUint8Array(str);
    let result = '';
    let buffer = 0;
    let bitsLeft = 0;

    for (let i = 0; i < uint8Array.length; i++) {
      buffer = (buffer << 8) | uint8Array[i];
      bitsLeft += 8;

      while (bitsLeft >= 5) {
        bitsLeft -= 5;
        result += alphabet[(buffer >>> bitsLeft) & 0x1f];
      }
    }

    if (bitsLeft > 0) {
      result += alphabet[(buffer << (5 - bitsLeft)) & 0x1f];
    }

    while (result.length % 8 !== 0) {
      result += '=';
    }

    return result;
  },

  /**
   * Base32解码
   * @param base32 要解码的Base32字符串
   * @returns 解码后的原始字符串
   */
  fromBase32(base32: string): string {
    if (!base32) return '';
    const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ234567';
    let buffer = 0;
    let bitsLeft = 0;
    const bytes: number[] = [];

    base32 = base32.replace(/=+$/, '').replace(/\s/g, '');

    for (let i = 0; i < base32.length; i++) {
      const char = base32[i].toUpperCase();
      const index = alphabet.indexOf(char);
      if (index === -1) continue;

      buffer = (buffer << 5) | index;
      bitsLeft += 5;

      if (bitsLeft >= 8) {
        bitsLeft -= 8;
        bytes.push((buffer >>> bitsLeft) & 0xff);
      }
    }

    return this.uint8ArrayToString(new Uint8Array(bytes));
  },

  /**
   * Base45编码
   * @param str 要编码的字符串
   * @returns Base45编码结果
   */
  toBase45(str: string): string {
    if (!str) return '';
    const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
    const uint8Array = this.stringToUint8Array(str);
    let result = '';

    for (let i = 0; i < uint8Array.length; i += 2) {
      if (i + 1 < uint8Array.length) {
        // 处理两个字节
        const value = (uint8Array[i] << 8) | uint8Array[i + 1];
        const e = value % 45;
        const d = Math.floor(value / 45) % 45;
        const c = Math.floor(value / 2025);
        result += alphabet[c] + alphabet[d] + alphabet[e];
      } else {
        // 处理最后一个字节
        const value = uint8Array[i];
        const d = Math.floor(value / 45);
        const e = value % 45;
        result += alphabet[d] + alphabet[e];
      }
    }

    return result;
  },

  /**
   * Base45解码
   * @param base45 要解码的Base45字符串
   * @returns 解码后的原始字符串
   */
  fromBase45(base45: string): string {
    if (!base45) return '';
    const alphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
    const bytes: number[] = [];

    for (let i = 0; i < base45.length;) {
      const remaining = base45.length - i;
      
      if (remaining >= 3) {
        // 处理三个字符
        const c = alphabet.indexOf(base45[i]);
        const d = alphabet.indexOf(base45[i + 1]);
        const e = alphabet.indexOf(base45[i + 2]);
        
        if (c === -1 || d === -1 || e === -1) {
          throw new Error(`Invalid Base45 character at position ${i}`);
        }

        const value = c * 2025 + d * 45 + e;
        if (value > 0xFFFF) {
          throw new Error(`Invalid Base45 value at position ${i}`);
        }

        bytes.push((value >> 8) & 0xFF);
        bytes.push(value & 0xFF);
        i += 3;
      } else if (remaining === 2) {
        // 处理两个字符
        const d = alphabet.indexOf(base45[i]);
        const e = alphabet.indexOf(base45[i + 1]);
        
        if (d === -1 || e === -1) {
          throw new Error(`Invalid Base45 character at position ${i}`);
        }

        const value = d * 45 + e;
        if (value > 0xFF) {
          throw new Error(`Invalid Base45 value at position ${i}`);
        }

        bytes.push(value);
        i += 2;
      } else {
        throw new Error('Invalid Base45 string length');
      }
    }

    return this.uint8ArrayToString(new Uint8Array(bytes));
  },

  /**
   * Base58编码
   * @param str 要编码的字符串
   * @returns Base58编码结果
   */
  toBase58(str: string): string {
    if (!str) return '';
    const alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
    const uint8Array = this.stringToUint8Array(str);
    let result = '';
    let leadingZeros = 0;
    
    // 计算前导零的数量
    while (uint8Array[leadingZeros] === 0) {
      leadingZeros++;
    }

    // 将字节数组转换为大数
    let num = BigInt(0);
    for (let i = 0; i < uint8Array.length; i++) {
      num = (num << BigInt(8)) | BigInt(uint8Array[i]);
    }

    // 转换为Base58
    while (num > BigInt(0)) {
      const remainder = Number(num % BigInt(58));
      num = num / BigInt(58);
      result = alphabet[remainder] + result;
    }

    return '1'.repeat(leadingZeros) + result;
  },

  /**
   * Base58解码
   * @param base58 要解码的Base58字符串
   * @returns 解码后的原始字符串
   */
  fromBase58(base58: string): string {
    if (!base58) return '';
    const alphabet = '123456789ABCDEFGHJKLMNPQRSTUVWXYZabcdefghijkmnopqrstuvwxyz';
    let leadingOnes = 0;
    
    // 计算前导1的数量
    while (base58[leadingOnes] === '1') {
      leadingOnes++;
    }

    base58 = base58.slice(leadingOnes);
    let num = BigInt(0);

    // 将Base58转换为大数
    for (let i = 0; i < base58.length; i++) {
      const index = alphabet.indexOf(base58[i]);
      if (index === -1) throw new Error('Invalid Base58 character');
      num = num * BigInt(58) + BigInt(index);
    }

    // 将大数转换为字节数组
    const bytes: number[] = [];
    while (num > BigInt(0)) {
      bytes.unshift(Number(num % BigInt(256)));
      num = num / BigInt(256);
    }

    // 添加前导零
    const result = new Uint8Array(leadingOnes + bytes.length);
    for (let i = 0; i < leadingOnes; i++) {
      result[i] = 0;
    }
    result.set(bytes, leadingOnes);

    return this.uint8ArrayToString(result);
  },

  /**
   * Base62编码
   * @param str 要编码的字符串
   * @param customAlphabet 自定义编码表（62个字符）
   * @returns Base62编码结果
   */
  toBase62(str: string, customAlphabet?: string): string {
    if (!str) return '';
    const defaultAlphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    const alphabet = customAlphabet || defaultAlphabet;
    if (alphabet.length !== 62) throw new Error('Base62 alphabet must be 62 characters long');

    const uint8Array = this.stringToUint8Array(str);
    let result = '';
    let num = BigInt(0);

    // 将字节数组转换为大数
    for (let i = 0; i < uint8Array.length; i++) {
      num = (num << BigInt(8)) | BigInt(uint8Array[i]);
    }

    // 转换为Base62
    while (num > BigInt(0)) {
      const remainder = Number(num % BigInt(62));
      num = num / BigInt(62);
      result = alphabet[remainder] + result;
    }

    return result || alphabet[0];
  },

  /**
   * Base62解码
   * @param base62 要解码的Base62字符串
   * @param customAlphabet 自定义编码表（62个字符）
   * @returns 解码后的原始字符串
   */
  fromBase62(base62: string, customAlphabet?: string): string {
    if (!base62) return '';
    const defaultAlphabet = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz';
    const alphabet = customAlphabet || defaultAlphabet;
    if (alphabet.length !== 62) throw new Error('Base62 alphabet must be 62 characters long');

    let num = BigInt(0);

    // 将Base62转换为大数
    for (let i = 0; i < base62.length; i++) {
      const index = alphabet.indexOf(base62[i]);
      if (index === -1) throw new Error('Invalid Base62 character');
      num = num * BigInt(62) + BigInt(index);
    }

    // 将大数转换为字节数组
    const bytes: number[] = [];
    while (num > BigInt(0)) {
      bytes.unshift(Number(num % BigInt(256)));
      num = num / BigInt(256);
    }

    return this.uint8ArrayToString(new Uint8Array(bytes));
  },

  /**
   * Base64编码
   * @param str 要编码的字符串
   * @returns Base64编码结果
   */
  toBase64(str: string): string {
    if (!str) return '';
    const uint8Array = this.stringToUint8Array(str);
    let base64 = '';
    const base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';

    for (let i = 0; i < uint8Array.length; i += 3) {
      const byte1 = uint8Array[i];
      const byte2 = uint8Array[i + 1];
      const byte3 = uint8Array[i + 2];

      const char1 = byte1 >> 2;
      const char2 = ((byte1 & 3) << 4) | (byte2 >> 4);
      const char3 = ((byte2 & 15) << 2) | (byte3 >> 6);
      const char4 = byte3 & 63;

      base64 += base64chars[char1] + base64chars[char2] +
        (byte2 !== undefined ? base64chars[char3] : '=') +
        (byte3 !== undefined ? base64chars[char4] : '=');
    }

    return base64;
  },

  /**
   * Base64解码
   * @param base64 要解码的Base64字符串
   * @returns 解码后的原始字符串
   */
  fromBase64(base64: string): string {
    if (!base64) return '';
    const base64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/';
    const bytes: number[] = [];

    base64 = base64.replace(/[^A-Za-z0-9+/=]/g, '');

    for (let i = 0; i < base64.length; i += 4) {
      const char1 = base64chars.indexOf(base64[i]);
      const char2 = base64chars.indexOf(base64[i + 1]);
      const char3 = base64chars.indexOf(base64[i + 2]);
      const char4 = base64chars.indexOf(base64[i + 3]);

      const byte1 = (char1 << 2) | (char2 >> 4);
      const byte2 = ((char2 & 15) << 4) | (char3 >> 2);
      const byte3 = ((char3 & 3) << 6) | char4;

      bytes.push(byte1);
      if (char3 !== -1) bytes.push(byte2);
      if (char4 !== -1) bytes.push(byte3);
    }

    return this.uint8ArrayToString(new Uint8Array(bytes));
  },

  /**
   * Base64URL编码（URL安全）
   * @param str 要编码的字符串
   * @returns Base64URL编码结果
   */
  toBase64URL(str: string): string {
    return this.toBase64(str)
      .replace(/\+/g, '-')
      .replace(/\//g, '_')
      .replace(/=+$/, '');
  },

  /**
   * Base64URL解码
   * @param base64url 要解码的Base64URL字符串
   * @returns 解码后的原始字符串
   */
  fromBase64URL(base64url: string): string {
    let base64 = base64url.replace(/-/g, '+').replace(/_/g, '/');
    while (base64.length % 4) {
      base64 += '=';
    }
    return this.fromBase64(base64);
  },

  /**
   * Base85编码
   * @param str 要编码的字符串
   * @returns Base85编码结果
   */
  toBase85(str: string): string {
    if (!str) return '';
    const alphabet = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu';
    const uint8Array = this.stringToUint8Array(str);
    let result = '';
    let buffer = 0;
    let count = 0;

    for (let i = 0; i < uint8Array.length; i++) {
      buffer = (buffer << 8) | uint8Array[i];
      count += 8;

      while (count >= 5) {
        count -= 5;
        const index = (buffer >>> count) & 0x1f;
        result += alphabet[index];
      }
    }

    if (count > 0) {
      const index = (buffer << (5 - count)) & 0x1f;
      result += alphabet[index];
    }

    return result;
  },

  /**
   * Base85解码
   * @param base85 要解码的Base85字符串
   * @returns 解码后的原始字符串
   */
  fromBase85(base85: string): string {
    if (!base85) return '';
    const alphabet = '!"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstu';
    let buffer = 0;
    let count = 0;
    const bytes: number[] = [];

    for (let i = 0; i < base85.length; i++) {
      const char = base85[i];
      const index = alphabet.indexOf(char);
      if (index === -1) continue;

      buffer = (buffer << 5) | index;
      count += 5;

      if (count >= 8) {
        count -= 8;
        bytes.push((buffer >>> count) & 0xff);
      }
    }

    return this.uint8ArrayToString(new Uint8Array(bytes));
  },

  /**
   * Base91编码
   * @param str 要编码的字符串
   * @returns Base91编码结果
   */
  toBase91(str: string): string {
    if (!str) return '';
    const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"';
    const uint8Array = this.stringToUint8Array(str);
    let buffer = 0;
    let bitsLeft = 0;
    let result = '';

    for (let i = 0; i < uint8Array.length; i++) {
      buffer |= uint8Array[i] << bitsLeft;
      bitsLeft += 8;

      while (bitsLeft > 13) {
        let value = buffer & 0x1fff;
        if (value > 88) {
          buffer >>= 13;
          bitsLeft -= 13;
        } else {
          value = buffer & 0x3fff;
          buffer >>= 14;
          bitsLeft -= 14;
        }
        result += alphabet[value % 91] + alphabet[Math.floor(value / 91)];
      }
    }

    if (bitsLeft > 0) {
      result += alphabet[buffer % 91];
      if (bitsLeft > 7 || buffer > 90) {
        result += alphabet[Math.floor(buffer / 91)];
      }
    }

    return result;
  },

  /**
   * Base91解码
   * @param base91 要解码的Base91字符串
   * @returns 解码后的原始字符串
   */
  fromBase91(base91: string): string {
    if (!base91) return '';
    const alphabet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789!#$%&()*+,./:;<=>?@[]^_`{|}~"';
    let buffer = 0;
    let bitsLeft = 0;
    const bytes: number[] = [];
    let v = -1;

    for (let i = 0; i < base91.length; i++) {
      const char = base91[i];
      const index = alphabet.indexOf(char);
      if (index === -1) continue;

      if (v < 0) {
        v = index;
      } else {
        v += index * 91;
        buffer |= v << bitsLeft;
        bitsLeft += (v & 0x1fff) > 88 ? 13 : 14;

        while (bitsLeft > 7) {
          bytes.push(buffer & 0xff);
          buffer >>= 8;
          bitsLeft -= 8;
        }

        v = -1;
      }
    }

    if (v > -1) {
      bytes.push((buffer | v << bitsLeft) & 0xff);
    }

    return this.uint8ArrayToString(new Uint8Array(bytes));
  },

  /**
   * Base100编码（Emoji编码）
   * @param str 要编码的字符串
   * @returns Emoji编码结果
   */
  toBase100(str: string): string {
    if (!str) return '';
    const uint8Array = this.stringToUint8Array(str);
    let result = '';
    
    // 使用 Uint8Array 处理每个字节
    for (let i = 0; i < uint8Array.length; i++) {
      const byte = uint8Array[i];
      // 将字节映射到 Emoji 区域 (0x1F300 - 0x1F3FF)
      const emojiCode = byte + 0x1F300;
      result += String.fromCodePoint(emojiCode);
    }
    
    return result;
  },

  /**
   * Base100解码（Emoji解码）
   * @param emojiStr 要解码的Emoji字符串
   * @returns 解码后的原始字符串
   */
  fromBase100(emojiStr: string): string {
    if (!emojiStr) return '';
    const bytes: number[] = [];
    
    // 处理每个 Emoji 字符
    for (let i = 0; i < emojiStr.length; i++) {
      const codePoint = emojiStr.codePointAt(i);
      if (codePoint && codePoint >= 0x1F300 && codePoint <= 0x1F3FF) {
        // 从 Emoji 区域映射回原始字节
        const byte = codePoint - 0x1F300;
        bytes.push(byte);
      }
    }
    
    return this.uint8ArrayToString(new Uint8Array(bytes));
  },

  /**
   * URL安全编码
   * @param str 要编码的URL字符串
   * @returns URL编码结果
   */
  encodeURL(str: string): string {
    return encodeURIComponent(str)
      .replace(/[!'()*]/g, c => `%${c.charCodeAt(0).toString(16).toUpperCase()}`);
  },

  /**
   * URL安全解码
   * @param encoded 要解码的URL字符串
   * @returns 解码后的原始字符串
   */
  decodeURL(encoded: string): string {
    return decodeURIComponent(encoded.replace(/\+/g, ' '));
  },

  /**
   * 摩斯电码编码
   * @param str 要编码的字符串
   * @param separator 分隔符，默认为'/'
   * @returns 摩斯电码编码结果
   */
  toMorse(str: string, separator: string = '/'): string {
    if (!str) return '';
    const morseMap: Record<string, string> = {
      'A': '.-',    'B': '-...',  'C': '-.-.', 'D': '-..',
      'E': '.',     'F': '..-.',  'G': '--.',  'H': '....',
      'I': '..',    'J': '.---',  'K': '-.-',  'L': '.-..',
      'M': '--',    'N': '-.',    'O': '---',  'P': '.--.',
      'Q': '--.-',  'R': '.-.',   'S': '...',  'T': '-',
      'U': '..-',   'V': '...-',  'W': '.--',  'X': '-..-',
      'Y': '-.--',  'Z': '--..',
      '0': '-----', '1': '.----', '2': '..---', '3': '...--',
      '4': '....-', '5': '.....', '6': '-....', '7': '--...',
      '8': '---..', '9': '----.',
      ' ': ' '
    };

    return str.toUpperCase().split('').map(char => {
      if (char === ' ') {
        return ' ';
      }
      return morseMap[char] || char;
    }).join(separator);
  },

  /**
   * 摩斯电码解码
   * @param morse 要解码的摩斯电码
   * @param separator 分隔符，默认为'/'
   * @returns 解码后的原始字符串
   */
  fromMorse(morse: string, separator: string = '/'): string {
    if (!morse) return '';
    const reverseMap: Record<string, string> = {
      '.-': 'A',    '-...': 'B',  '-.-.': 'C',  '-..': 'D',
      '.': 'E',     '..-.': 'F',  '--.': 'G',   '....': 'H',
      '..': 'I',    '.---': 'J',  '-.-': 'K',   '.-..': 'L',
      '--': 'M',    '-.': 'N',    '---': 'O',   '.--.': 'P',
      '--.-': 'Q',  '.-.': 'R',   '...': 'S',   '-': 'T',
      '..-': 'U',   '...-': 'V',  '.--': 'W',   '-..-': 'X',
      '-.--': 'Y',  '--..': 'Z',
      '-----': '0', '.----': '1', '..---': '2', '...--': '3',
      '....-': '4', '.....': '5', '-....': '6', '--...': '7',
      '---..': '8', '----.': '9',
      ' ': ' '
    };

    return morse.split(separator).map(code => {
      if (code === ' ') {
        return ' ';
      }
      return reverseMap[code] || code;
    }).join('');
  }
};